package cn.ucox.web.ms.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 抽象平台异常
 *
 * @author chenw
 * @email javacspring@gmail.com
 * @time 2016-11-10 16:22
 */
public abstract class BasicException extends Exception {

    private static final Logger logger = LoggerFactory.getLogger(BasicException.class);

    protected static final int CODE_CACHE_INVALIDATION_EXCEPTION = 100506;//缓存失效
    protected static final int CODE_CACHE_OPERATION_EXCEPTION = 100509;//缓存操作异常

    public static enum Action {

        CREATE(1), UPDATE(2), READ(3), DELETE(4);

        private int value;

        Action(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }


    private static final String EXCEPTION_TRACE_FILTER = "cn.ucox";
    private Map<String, Object> report;
    private int code;

    protected BasicException(int errorCode, String message) {
        super(message);
        this.code = errorCode;
        this.report = new HashMap<String, Object>(4) {{
            put("code", errorCode);
            put("msg", message);
            put("time", System.currentTimeMillis());
            String filter = getFilter();
            if (logger.isDebugEnabled()) {
                put("data", getData());
                if (StringUtils.isEmpty(filter))
                    put("trace", getStackTrace());
                else {
                    put("trace", Stream
                            .of(getStackTrace())
                            .filter(trace -> trace.getClassName().startsWith(filter))
                            .collect(Collectors.toList()));
                    put("format", getFormatTrace(get("trace")));
                }
            }
        }};
    }

    public Map<String, Object> getReport() {
        return report;
    }

    /**
     * 获取格式化堆栈信息
     *
     * @return 格式化堆栈信息
     */
    public static String getFormatTrace(Object exception) {
        if (null != exception) {
            StackTraceElement[] traces;
            if (exception instanceof ArrayList) {
                ArrayList<StackTraceElement> originTraces = (ArrayList<StackTraceElement>) exception;
                traces = originTraces.toArray(new StackTraceElement[originTraces.size()]);
            } else {
                traces = (StackTraceElement[]) exception;
            }

            StringBuilder err = new StringBuilder();
            int level = 0;
            for (StackTraceElement traceElement : traces) {
                level++;
                err.append("\n|");
                for (int j = 0; j < level; j++) {
                    err.append("_");
                }
                err.append(String.format("%s.%s() ->%d",
                        traceElement.getClassName(),
                        traceElement.getMethodName(),
                        traceElement.getLineNumber()));
            }
            return err.toString();
        } else {
            return "";
        }
    }

    public int getCode() {
        return this.code;
    }

    protected String getFilter() {
        return EXCEPTION_TRACE_FILTER;
    }

    public abstract Object getData();
}
